package com.woniuxy.ticketauth.shiro;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.commnes.entity.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;

import javax.servlet.Filter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;

/**
 * @ClassName JwtFilter
 * @Description 自定义过滤器，用户JWT认证的效验
 * @Author zx
 * @Date 2021-03-03 15:56:22
 * @Version 1.0
 */
@Slf4j
public class JwtFilter extends AuthenticatingFilter {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        String jwtToken = ((HttpServletRequest) request).getHeader("jwt");
        return new JwtToken(jwtToken);
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response,Object mappedValue) {
        if (this.isLoginRequest(request, response))
            return true;
        boolean allowed = false;
        try {
            allowed = executeLogin(request, response);
        } catch (IllegalStateException e) { // not found any token
            log.error("Not found any token");
        } catch (Exception e) {
            log.error("Error occurs when login", e);
        }
        ShiroFilterFactoryBean shiroFilterFactoryBean = applicationContext.getBean(ShiroFilterFactoryBean.class);
        response.setContentType("application/json; charset=UTF-8");
        try {
            if (allowed) {
                Map<String, String> filterMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
                //获取到当前访问的URL
                String requestURI = ((HttpServletRequest) request).getRequestURI();
                if (requestURI.equals("/menu/get")) {
                    return true;
                }
                //获取该URL所需经过的过滤器
                String filters = filterMap.get(requestURI);  //  jwt,perms[order,add]
                String[] split = filters.replaceAll("(\\[(.*?)])", "").split(",");
                String s = split[split.length - 1];
                Map<String, Filter> map = shiroFilterFactoryBean.getFilters();
                //根据过滤器的名字找到具体的过滤器的类
                Filter lastFilter = map.get(s);
                //判断当前的过滤器类是否是该URL所需过滤器中的最后一个
                //if(是最后一个)  return false
                //else return true;
                if (lastFilter.getClass() == this.getClass()) {
                    ObjectMapper objectMapper = new ObjectMapper();
                    response.getWriter().write(objectMapper.writeValueAsString(ResponseResult.SUCCESS));
                    return false;
                } else {
                    return true;
                }
            } else {
                ResponseResult<Void> result = new ResponseResult<>(407, "会话失效，重新登录");
                ObjectMapper objectMapper = new ObjectMapper();
                response.getWriter().write(objectMapper.writeValueAsString(result));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        return isAccessAllowed(request, response, mappedValue);
    }

    /**
     * 登录成功
     *
     * @param token
     * @param subject
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {
        //为Jwt自动续期
        return super.onLoginSuccess(token, subject, request, response);
    }

    /**
     * 没有认证那么就进入这个方法
     *
     * @param request
     * @param response
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        ResponseResult<Void> result = new ResponseResult<>(403, "会话失效，重新登录");
        ObjectMapper objectMapper = new ObjectMapper();
        response.getWriter().write(objectMapper.writeValueAsString(result));
        return false;
    }
}
